const fs = require("fs");
const path = require("path");
const mongo = require("./mongo");
const models = require("./mysql");
const process = require("process");
const dbg = require("debug")("[after-read]");
dbg.enabled = true;
let store = {
    count: 0
}
/**
 * @description 全部存储到数据库里面以后，重新读出来，写成若干个文件
 * @returns {Promise}
 */
function AfterRead() {

    return new Promise((resolve) => {
        mongo.MhtFile.findOne().then(doc => {
            let boundary = doc['boundary'];
            let filename = doc['filename'];
            // debugger
            let g = (function* Generator() {
                while (true) {
                    yield WriteAsEml(500, boundary, filename);
                }
            })();
            let it = g.next();
            let write_emls_promise = new Promise((r) => {
                (function Boot() {
                    // debugger
                    if (!it.done) {
                        it.value.then(() => {
                            it = g.next();
                            Boot();
                        }).catch(err => {
                            g.return("it seems empty htmls occured");
                            r("empty htmls");
                        })
                    } else {
                        r("Boot done?");
                    }
                })();
            });
            write_emls_promise.then(() => {
                // store
                Promise.all([
                    mongo.HtmlMsg.deleteMany({
                        boundary: boundary,
                        visited: true
                    }),
                    mongo.Image.deleteMany({
                        boundary: boundary
                    }),
                    mongo.MhtFile.deleteMany({
                        boundary: boundary
                    })
                ]).then(args => resolve("all done"));
            })


        })
    })
};
/**
 * @description 从数据库中取出html和image，写入.eml文件
 * @param {Number} limit 限制每个.eml文件里的html行数
 * @param {String} boundary
 * @param {String} filename
 */
function WriteAsEml(limit, boundary, filename) {
    return new Promise((resolve, reject) => {
        /**@type {String[]} htmls */
        let htmls = [];
        let images = [];

        function CollectHtmls() {
            return new Promise(r => {
                function* Generator() {
                    for (let i = 1; i <= limit; i++) {
                        yield PickHtmlAndMark(boundary);
                    }
                }
                let g = Generator();
                let it = g.next();
                let boot = function boot() {
                    if (!it.done) {
                        it.value.then(html => {
                            htmls.push(html);
                            it = g.next();
                            boot();
                        }).catch(err => {
                            g.return("no more");
                            r("done");
                        })
                    } else {
                        r("done")
                    }
                };
                boot()

            })
        };

        function CollectImages() {
            return new Promise(r => {
                let cids = [];
                for (let html of htmls) {
                    let html_matched = html.match(/<IMG src="cid:([a-zA-Z0-9\-])+">/gi);
                    if (Array.isArray(html_matched)) {
                        for (let matched_img of html_matched) {
                            cids.push(matched_img.match(/"cid:([a-zA-Z0-9\-]+)"/)[1]);
                        }
                    }
                }
                let ps = cids.map(cid => PickImageByCid(cid));
                Promise.all(ps).then(imgs => {
                    imgs.filter(e => e !== null).forEach(image => images.push(image));
                    r("collect images done");
                })
            })
        }
        CollectHtmls()
            .then(nonesense => {
                return CollectImages()
            })
            .then(() => {
                /** 
                 * @description 根据暂存的images和html，以及count和boundary，拼凑出一个新的eml文件，写入磁盘（暂且——dirname），添加count以后resolve
                 *  如果htmls的长度为0,说明已经到了尽头，对应boundary已经全部提取完了，reject一下
                 */
                if (htmls.length) {
                    store.count++;
                    fs.writeFile(
                        path.join(process.cwd(), `${boundary}-${store.count}.eml`),
                        makeEmlTextByHtmlsAndImages(htmls, images, boundary, filename),
                        (err) => {
                            if (err) {
                                dbg("写文件出错", err);
                                resolve(err);
                            } else {
                                resolve(`done ${store.count} th.eml`)
                            }
                        }
                    )
                } else {
                    reject("zero length htmls");
                }
            })
    });
}

/**
 * @param {String} boundary
 * @description 按照时间顺序取出1条没有visited的html，并且标记成visited
 * @returns {Promise} 正常情况下resolve返回html，找不到的情况下reject
 */
function PickHtmlAndMark(boundary) {
    return new Promise((resolve, reject) => {
        mongo.HtmlMsg.findOneAndUpdate({
            visited: false,
            boundary: boundary
        }, {
            visited: true
        }).then(doc => {
            if (doc) {
                resolve(doc['html'])
            } else {
                reject("no more unvisited html")
            }
        })
    })
}

/**
 * 
 * @param {String} cid 
 */
function PickImageByCid(cid) {
    return new Promise((resolve) => {
        /** 
         * @todo 根据cid找到相应图片，置visited为false，resolve{cid，content}
         * @todo 万一找不到也是resolve个null，不使用reject
         */
        mongo.Image.findOne({
            cid: cid
        }).then(doc => {
            if (doc) {
                let image = {
                    image_type: doc['image_type'],
                    cid: doc['cid'],
                    content: doc['content']
                };
                mongo
                    .Image
                    .updateOne({
                        cid: cid
                    }, {
                        visited: true
                    })
                    .then(() => {
                        resolve(image)
                    })

            } else {
                resolve(null);
            }
        })
    })
}

/**
 * 
 * @param {String[]} htmls 
 * @param {Array<{cid:String,content:String,image_type:String}>} images 
 * @param {String} boundary
 * @param {String} filename
 * @returns {String}
 */
function makeEmlTextByHtmlsAndImages(htmls, images, boundary, filename) {
    let head = `Subject:[QQ-MHT] ${filename}-${store.count}\n`;
    head += `MIME-Version: 1.0\n`;
    head += `Content-Type:multipart/related;\n`;
    head += `\tcharset="utf-8"\n`;
    head += `\ttype="text/html";\n`;
    head += `\tboundary="${boundary}"\n\r\n`;
    let html_part = `--${boundary}\n`;
    html_part += `Content-Type: text/html\nContent-Transfer-Encoding:7bit\n\r\n`;
    html_part += `<html xmlns="http://www.w3.org/1999/xhtml"><head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>QQ Message</title>
    <style type="text/css">body{font-size:12px; line-height:22px; margin:2px;}td{font-size:12px; line-height:22px;}</style></head><body>
    <h1>This file was created by <a href="https://github.com/HujiLee"><font color="#ff0080">Hujimiya</font></a></h1>
    <table width=100% cellspacing=0>\n`;
    html_part += htmls.join("\n");
    html_part += `</table></body></html>\n`;
    let image_part = images.map(image => {
        let text = `--${boundary}\n`;
        text += `Content-Type:${image.image_type}\n`;
        text += `Content-Transfer-Encoding:base64\n`;
        text += `Content-ID:<${image.cid}>\n\r`;
        text += "\n";
        text += `${image.content}\n\r\n`;
        return text;
    }).join("");
    return head + html_part + image_part + `\r\n--${boundary}--\r\n`
}

module.exports = {
    AfterRead
}